"""
视频生成模块
根据剪辑决策生成最终的视频文件
"""
import logging
import os
import tempfile
from typing import Dict, List, Any, Optional
from moviepy.editor import (
    VideoFileClip, TextClip, CompositeVideoClip,
    AudioFileClip, concatenate_videoclips, vfx, afx
)
from moviepy.video.fx import resize, fadein, fadeout
from moviepy.audio.fx import volumex
import numpy as np
from app.exceptions import VideoGenerationError
from app.config import settings

logger = logging.getLogger(__name__)


class VideoGenerator:
    """视频生成器"""

    def __init__(self):
        self.temp_dir = tempfile.gettempdir()

    async def generate_video(
        self,
        original_video_path: str,
        editing_decision: Dict[str, Any],
        output_path: str,
        progress_callback=None
    ) -> Dict[str, Any]:
        """
        生成最终视频

        Args:
            original_video_path: 原始视频路径
            editing_decision: 剪辑决策
            output_path: 输出路径
            progress_callback: 进度回调函数

        Returns:
            生成���果信息
        """
        try:
            logger.info(f"Starting video generation for: {original_video_path}")

            if progress_callback:
                progress_callback("加载原始视频", 5)

            # 加载原始视频
            original_clip = VideoFileClip(original_video_path)

            if progress_callback:
                progress_callback("提取视频片段", 20)

            # 提选视频片段
            video_clips = await self._extract_video_clips(
                original_clip, editing_decision["segments"]
            )

            if not video_clips:
                raise VideoGenerationError("没有可用的视频片段")

            if progress_callback:
                progress_callback("添加转场效果", 40)

            # 添加转场效果
            processed_clips = await self._add_transitions(
                video_clips, editing_decision["editing_instructions"]
            )

            if progress_callback:
                progress_callback("添加开头和结尾", 60)

            # 添加开头和结尾
            final_clips = await self._add_intro_outro(
                processed_clips, editing_decision, original_clip.size
            )

            if progress_callback:
                progress_callback("添加字幕", 75)

            # 添加字幕
            final_video = await self._add_subtitles(
                final_clips, editing_decision["segments"]
            )

            if progress_callback:
                progress_callback("生成最终视频", 90)

            # 生成最终视频
            final_video.write_videofile(
                output_path,
                codec='libx264',
                audio_codec='aac',
                temp_audiofile=os.path.join(self.temp_dir, 'temp_audio.m4a'),
                remove_temp=True,
                fps=24,
                preset='medium',
                threads=4
            )

            # 生成缩略图
            thumbnail_path = await self._generate_thumbnail(final_video, output_path)

            # 清理资源
            final_video.close()
            original_clip.close()

            if progress_callback:
                progress_callback("视频生成完成", 100)

            result = {
                "output_path": output_path,
                "thumbnail_path": thumbnail_path,
                "duration": final_video.duration,
                "size": os.path.getsize(output_path),
                "segments_count": len(editing_decision["segments"])
            }

            logger.info("Video generation completed successfully")
            return result

        except Exception as e:
            logger.error(f"Video generation failed: {e}")
            raise VideoGenerationError(f"视频生成失败: {e}")

    async def _extract_video_clips(
        self,
        original_clip: VideoFileClip,
        segments: List[Dict[str, Any]]
    ) -> List[VideoFileClip]:
        """提取视频片段"""
        clips = []

        for segment in segments:
            start_time = segment["start_time"]
            end_time = segment["end_time"]

            try:
                # 提取片段
                clip = original_clip.subclip(start_time, end_time)
                clips.append(clip)
                logger.debug(f"Extracted clip: {start_time}-{end_time}")

            except Exception as e:
                logger.warning(f"Failed to extract clip {start_time}-{end_time}: {e}")
                continue

        return clips

    async def _add_transitions(
        self,
        clips: List[VideoFileClip],
        editing_instructions: Dict[str, Any]
    ) -> List[VideoFileClip]:
        """添加转场效果"""
        transition_style = editing_instructions.get("transition_style", "cut")

        if len(clips) <= 1:
            return clips

        processed_clips = []

        for i, clip in enumerate(clips):
            if i == 0:
                # 第一个片段
                if transition_style == "fade":
                    processed_clips.append(clip.fadein(0.5))
                elif transition_style == "slide":
                    # 添加滑动效果（简化版本）
                    processed_clips.append(clip.fadein(0.3))
                else:
                    processed_clips.append(clip)
            else:
                # 后续片段
                if transition_style == "fade":
                    # 淡入淡出
                    previous_clip = processed_clips[-1].fadeout(0.3)
                    current_clip = clip.fadein(0.3)
                    processed_clips[-1] = previous_clip
                    processed_clips.append(current_clip)
                elif transition_style == "dissolve":
                    # 溶解效果（简化为淡入淡出）
                    previous_clip = processed_clips[-1].fadeout(0.5)
                    current_clip = clip.fadein(0.5)
                    processed_clips[-1] = previous_clip
                    processed_clips.append(current_clip)
                else:
                    # 直接切换
                    processed_clips.append(clip)

        return processed_clips

    async def _add_intro_outro(
        self,
        clips: List[VideoFileClip],
        editing_decision: Dict[str, Any],
        video_size: tuple
    ) -> List[VideoFileClip]:
        """添加开头和结尾"""
        template_config = editing_decision["template_config"]
        final_clips = []

        # 添加开头
        if template_config.get("editing_rules", {}).get("add_intro", False):
            intro_duration = template_config.get("opening_duration", 3)
            intro_clip = await self._create_intro_clip(intro_duration, video_size)
            final_clips.append(intro_clip)

        # 添加主要内容
        final_clips.extend(clips)

        # 添加结尾
        if template_config.get("editing_rules", {}).get("add_outro", False):
            outro_duration = template_config.get("ending_duration", 2)
            outro_clip = await self._create_outro_clip(outro_duration, video_size)
            final_clips.append(outro_clip)

        return final_clips

    async def _create_intro_clip(self, duration: float, video_size: tuple) -> VideoFileClip:
        """创建开头片段"""
        try:
            # 创建黑色背景
            background = VideoFileClip("color:" + "black", duration=duration, size=video_size)

            # 添加标题文本
            title_text = "智能视频重构"
            subtitle_text = editing_decision.get("template_config", {}).get("name", "短视频")

            title_clip = TextClip(
                title_text,
                fontsize=50,
                color='white',
                font='SimHei',  # 使用中文字体
                align='center'
            ).set_duration(duration).set_position('center')

            subtitle_clip = TextClip(
                subtitle_text,
                fontsize=30,
                color='gray',
                font='SimHei',
                align='center'
            ).set_duration(duration).set_position(('center', video_size[1] * 0.6))

            # 合成视频
            intro = CompositeVideoClip([background, title_clip, subtitle_clip])
            return intro

        except Exception as e:
            logger.warning(f"Failed to create intro clip: {e}")
            # 返回简单的黑色背景
            return VideoFileClip("color:black", duration=duration, size=video_size)

    async def _create_outro_clip(self, duration: float, video_size: tuple) -> VideoFileClip:
        """创建结尾片段"""
        try:
            # 创建黑色背景
            background = VideoFileClip("color:black", duration=duration, size=video_size)

            # 添加结束文本
            end_text = "感谢观看"
            end_clip = TextClip(
                end_text,
                fontsize=40,
                color='white',
                font='SimHei',
                align='center'
            ).set_duration(duration).set_position('center')

            # 合成视频
            outro = CompositeVideoClip([background, end_clip])
            return outro

        except Exception as e:
            logger.warning(f"Failed to create outro clip: {e}")
            # 返回简单的黑色背景
            return VideoFileClip("color:black", duration=duration, size=video_size)

    async def _add_subtitles(
        self,
        clips: List[VideoFileClip],
        segments: List[Dict[str, Any]]
    ) -> VideoFileClip:
        """添加字幕"""
        try:
            # 拼接所有片段
            if len(clips) == 1:
                final_video = clips[0]
            else:
                final_video = concatenate_videoclips(clips, method="compose")

            # 如果不需要字幕，直接返回
            if not settings.ENABLE_SUBTITLE_GENERATION:
                return final_video

            # 创建字幕片段
            subtitle_clips = []
            current_time = 0

            for segment in segments:
                text = segment.get("text", "").strip()
                if text:
                    # 创建字幕
                    subtitle = TextClip(
                        text,
                        fontsize=24,
                        color='white',
                        font='SimHei',
                        stroke_color='black',
                        stroke_width=1,
                        align='center'
                    ).set_duration(segment["duration"]).set_start(current_time)

                    # 设置字幕位置（底部）
                    subtitle = subtitle.set_position(('center', final_video.h * 0.85))
                    subtitle_clips.append(subtitle)

                current_time += segment["duration"]

            # 合成最终视频
            if subtitle_clips:
                final_video = CompositeVideoClip([final_video] + subtitle_clips)

            return final_video

        except Exception as e:
            logger.warning(f"Failed to add subtitles: {e}")
            # 如果字幕添加失败，返回原视频
            if len(clips) == 1:
                return clips[0]
            else:
                return concatenate_videoclips(clips, method="compose")

    async def _generate_thumbnail(self, video_clip: VideoFileClip, video_path: str) -> str:
        """生成视频缩略图"""
        try:
            # 在视频中间位置截取一帧
            middle_time = video_clip.duration / 2
            thumbnail_path = video_path.replace('.mp4', '_thumbnail.jpg')

            # 保存缩略图
            video_clip.save_frame(thumbnail_path, t=middle_time)

            return thumbnail_path

        except Exception as e:
            logger.warning(f"Failed to generate thumbnail: {e}")
            return ""